package com.collection.util;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.util.Base64Utils;
import org.springframework.web.multipart.MultipartFile;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.Bucket;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;


/**
 * @descript:java使用阿里云OSS存储对象上传图片
 */
public class OssUtil {
    // log日志
    private static Logger logger            = Logger.getLogger(OssUtil.class);
    
  //阿里云API的内或外网域名
    private static String ENDPOINT = "oss-cn-beijing.aliyuncs.com";
    //阿里云API的密钥Access Key ID
    private static String ACCESS_KEY_ID = "vxvDfbmso9LsYzeK";
    //阿里云API的密钥Access Key Secret
    private static String ACCESS_KEY_SECRET = "yVISMCsSHfiQlIPBxHGol1gZjkRl4X";
    //阿里云API的bucket名称
    public static String BACKET_NAME = "youhuhu";
    //阿里云API的文件夹名称
    public static String FOLDER = "youhuhu/";

    // 阿里云API的文件夹名称
    public static String  MOSAIC_FOLDER            = "youhuhu/";
    
    public static String accessUrl = "http://youhuhu.oss-cn-beijing.aliyuncs.com";
    /**
     * 获取阿里云OSS客户端对象
     * 
     * @return ossClient
     */
    public static OSSClient getOSSClient() {
        return new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
    }

    /**
     * 创建存储空间
     * 
     * @param ossClient OSS连接
     * @param bucketName 存储空间
     * @return
     */
    public static String createBucketName(OSSClient ossClient,
                                          String bucketName) {
        // 存储空间
        final String bucketNames = bucketName;
        if (!ossClient.doesBucketExist(bucketName)) {
            // 创建存储空间
            Bucket bucket = ossClient.createBucket(bucketName);
            logger.info("创建存储空间成功");
            return bucket.getName();
        }
        return bucketNames;
    }

    /**
     * 删除存储空间buckName
     * 
     * @param ossClient oss对象
     * @param bucketName 存储空间
     */
    public static void deleteBucket(OSSClient ossClient,
                                    String bucketName) {
        ossClient.deleteBucket(bucketName);
        logger.info("删除" + bucketName + "Bucket成功");
    }

    /**
     * 创建模拟文件夹
     * 
     * @param ossClient oss连接
     * @param bucketName 存储空间
     * @param folder 模拟文件夹名如"qj_nanjing/"
     * @return 文件夹名
     */
    public static String createFolder(OSSClient ossClient,
                                      String bucketName,
                                      String folder) {
        // 文件夹名
        final String keySuffixWithSlash = folder;
        // 判断文件夹是否存在，不存在则创建
        if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) {
            // 创建文件夹
            ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
            logger.info("创建文件夹成功");
            // 得到文件夹名
            OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
            String fileDir = object.getKey();
            return fileDir;
        }
        return keySuffixWithSlash;
    }

    /**
     * 根据key删除OSS服务器上的文件
     * 
     * @param ossClient oss连接
     * @param bucketName 存储空间
     * @param folder 模拟文件夹名 如"qj_nanjing/"
     * @param key Bucket下的文件的路径名+文件名 如："upload/cake.jpg"
     */
    public static void deleteFile(OSSClient ossClient,
                                  String bucketName,
                                  String folder,
                                  String key) {
        ossClient.deleteObject(bucketName, folder + key);
        logger.info("删除" + bucketName + "下的文件" + folder + key + "成功");
    }
    
    /**
     * 上传图片至OSS
     * 
     * @param ossClient oss连接
     * @param file 上传文件（文件全路径如：D:\\image\\cake.jpg）
     * @param bucketName 存储空间
     * @param folder 模拟文件夹名 如"qj_nanjing/"
     * @return String 返回的唯一MD5数字签名
     */
    public static UploadImgInfo uploadPic2OSS(MultipartFile multipartfile ,
                                          String bucketName,
                                          String folder) {
        OSSClient ossClient = getOSSClient();
        createBucketName(ossClient,bucketName);
        UploadImgInfo resultInfo = null;
        InputStream is = null;
        try {
            // 以输入流的形式上传文件
            is = multipartfile.getInputStream();
            // 文件名
            String orgName = multipartfile.getOriginalFilename();
            String ext = FilenameUtils.getExtension(orgName).toLowerCase();
            String fileName =  UuidUtil.getUUID()+"."+ext;
            String contextType= getContentType(multipartfile.getOriginalFilename());
            
           
            // 文件大小
            Long fileSize = multipartfile.getSize();
            
            logger.info("上传图片至OSS orgName----:"+orgName+"ext:"+ext+"fileName:"+fileName+"fileSize:"+fileSize);
            // 创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
            // 上传的文件的长度
            metadata.setContentLength(is.available());
            // 指定该Object被下载时的网页的缓存行为
            metadata.setCacheControl("no-cache");
            // 指定该Object下设置Header
            metadata.setHeader("Pragma", "no-cache");
            // 指定该Object被下载时的内容编码格式
            metadata.setContentEncoding("utf-8");
            // 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
            // 如果没有扩展名则填默认值application/octet-stream
            metadata.setContentType(contextType);
            // 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
            metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
            // 上传文件 (上传文件流的形式)
            PutObjectResult putResult = ossClient.putObject(bucketName, folder + fileName, is, metadata);
            System.out.println("上传解析结构+++++" + putResult);
            // 解析结果
            String resultStr = putResult.getETag();
            if (StringUtils.isNotEmpty(resultStr)) {
                resultInfo = new OssUtil.UploadImgInfo();
                String key = folder + fileName;
                String url = getUrl(ossClient,key);
                resultInfo.setUrl(url);
                resultInfo.setKey(key);
                String imgPath_original = url.substring(url.indexOf(ENDPOINT)+ENDPOINT.length());
                resultInfo.setImgPath_original(imgPath_original);
                resultInfo.setFile_name(fileName);
                //缩略图
                String turl = getResizeUrl(key,100);
                resultInfo.setUrl_thumbnail(turl);
                String imgPath_thumbnail = turl.substring(url.indexOf(ENDPOINT)+ENDPOINT.length());
                resultInfo.setImgPath_thumbnail(imgPath_thumbnail);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
        }finally {
            try {
                is.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
        }
        return resultInfo;
    }

    /**
     * 上传图片至OSS
     * 
     * @param ossClient oss连接
     * @param file 上传文件（文件全路径如：D:\\image\\cake.jpg）
     * @param bucketName 存储空间
     * @param folder 模拟文件夹名 如"qj_nanjing/"
     * @return String 返回的唯一MD5数字签名
     */
    public static UploadImgInfo uploadObject2OSS(OSSClient ossClient,
                                          InputStream is,
                                          String bucketName,
                                          String folder,String ext) {
        UploadImgInfo resultInfo = null;
        String resultStr = null;
        try {
            // 以输入流的形式上传文件
            //InputStream is = new FileInputStream(file);
            // 文件名
            //String ext = FilenameUtils.getExtension(orgName).toLowerCase();
            String fileName =  UuidUtil.getUUID()+"."+ext;
           
            // 创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
            // 上传的文件的长度
            metadata.setContentLength(is.available());
            // 指定该Object被下载时的网页的缓存行为
            metadata.setCacheControl("no-cache");
            // 指定该Object下设置Header
            metadata.setHeader("Pragma", "no-cache");
            // 指定该Object被下载时的内容编码格式
            metadata.setContentEncoding("utf-8");
            // 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
            // 如果没有扩展名则填默认值application/octet-stream
            metadata.setContentType(getContentType(fileName));
            // 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
            //metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
            // 上传文件 (上传文件流的形式)
            PutObjectResult putResult = ossClient.putObject(bucketName, folder + fileName, is, metadata);
            System.out.println("上传解析结构+++++" + putResult);
            // 解析结果
            resultStr = putResult.getETag();
            if (StringUtils.isNotEmpty(resultStr)) {
                resultInfo = new OssUtil.UploadImgInfo();
                String key = folder + fileName;
                String url = getUrl(ossClient,key);
                resultInfo.setUrl(url);
                resultInfo.setKey(key);
                String imgPath_original = url.substring(url.indexOf(ENDPOINT)+ENDPOINT.length());
                resultInfo.setImgPath_original(imgPath_original);
                resultInfo.setFile_name(fileName);
              //缩略图
                String turl = getResizeUrl(key,100);
                resultInfo.setUrl_thumbnail(turl);
                String imgPath_thumbnail = turl.substring(url.indexOf(ENDPOINT)+ENDPOINT.length());
                resultInfo.setImgPath_thumbnail(imgPath_thumbnail);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
        }
        return resultInfo;
    }

    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     * 
     * @param fileName 文件名
     * @return 文件的contentType
     */
    public static String getContentType(String fileName) {
        // 文件的后缀名
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
        if (".bmp".equalsIgnoreCase(fileExtension)) {
            return "image/bmp";
        }
        if (".gif".equalsIgnoreCase(fileExtension)) {
            return "image/gif";
        }
        if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension) || ".png".equalsIgnoreCase(fileExtension)) {
            return "image/jpeg";
        }
        if (".html".equalsIgnoreCase(fileExtension)) {
            return "text/html";
        }
        if (".txt".equalsIgnoreCase(fileExtension)) {
            return "text/plain";
        }
        if (".vsd".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.visio";
        }
        if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.ms-powerpoint";
        }
        if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
            return "application/msword";
        }
        if (".xml".equalsIgnoreCase(fileExtension)) {
            return "text/xml";
        }
        // 默认返回类型
        return "image/jpeg";
    }

    /**
     * 获得url链接
     * 
     * @param key 文件在oos上的路径
     * @return
     */
    public static String getUrl(OSSClient ossClient,
                                String key) {
        // 设置URL过期时间为10年 3600 * 1000*24*365*10
        //Date expiration = new Date(new Date().getTime() + 3600 * 1000 * 24 * 365 * 10);
    	 Calendar c = Calendar.getInstance();
    	 Date data = c.getTime();
    	 c.add(Calendar.YEAR, 50);
    	 Date expiration = c.getTime();
        // 生成URL
        URL url = ossClient.generatePresignedUrl(BACKET_NAME, key, expiration);
        if (url != null) {
            return url.toString();
        }
        return null;
    }
    /**
     * 获得缩略图url链接（强制缩略成固定宽高）
     * 
     * @param key 文件在oos上的路径
     * @return
     */
    public static String getResizeUrl(String key,Integer length) {
        if(length==null){
            length = 100;
        }
        OSSClient ossClient = getOSSClient();
        // 图片处理样式  
        String style = "image/resize,m_fixed,w_"+length+",h_"+length;
        // 设置URL过期时间为10年 3600* 1000*24*365*10
        //Date expiration = new Date(new Date().getTime() + 3600 * 1000 * 24 * 365 * 10);
	   	 Calendar c = Calendar.getInstance();
		 Date data = c.getTime();
		 c.add(Calendar.YEAR, 50);
		 Date expiration = c.getTime();
        // 过期时间10分钟
        //Date expiration = new Date(new Date().getTime() + 1000 * 60 * 10 );
        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(BACKET_NAME, key, HttpMethod.GET);
        req.setExpiration(expiration);
        req.setProcess(style);
        URL signedUrl = ossClient.generatePresignedUrl(req);
        if (signedUrl != null) {
            return signedUrl.toString();
        }
        return null;
    }
    /**
     * 获得缩略图url链接（等比缩放，限定在矩形框内,默认将图缩略成宽度为100，高度为100，按长边优先）
     * 
     * @param key 文件在oos上的路径
     * @return
     */
    public static String getEqualRatioResizeUrl(String key,Integer length) {
        if(length==null){
            length = 100;
        }
        OSSClient ossClient = getOSSClient();
        // 图片处理样式  image/resize,m_fixed,h_100,w_100
        String style = "image/resize,m_lfit,h_"+length+",w_"+length;
        // 设置URL过期时间为10年 3600 * 1000*24*365*10
        //Date expiration = new Date(new Date().getTime() + 3600 * 1000 * 24 * 365 * 10);
	   	 Calendar c = Calendar.getInstance();
		 Date data = c.getTime();
		 c.add(Calendar.YEAR, 50);
		 Date expiration = c.getTime();
        // 过期时间10分钟
        //Date expiration = new Date(new Date().getTime() + 1000 * 60 * 10 );
        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(BACKET_NAME, key, HttpMethod.GET);
        req.setExpiration(expiration);
        req.setProcess(style);
        URL signedUrl = ossClient.generatePresignedUrl(req);
        if (signedUrl != null) {
            return signedUrl.toString();
        }
        return null;
    }
    
    // 测试
    public static void main(String[] args) throws FileNotFoundException {
       
        // 初始化OSSClient
        OSSClient ossClient = OssUtil.getOSSClient();
        // 上传文件
        String files = "d:/zm.png";
        String[] file = files.split(",");
        for (String filename : file) {
            System.out.println("filename:" + filename);
            File filess = new File(filename);
            InputStream is = new FileInputStream(filess);
            UploadImgInfo up = OssUtil.uploadObject2OSS(ossClient, is, BACKET_NAME, FOLDER,"");
            System.out.println("------------"+up.getUrl());
            String[] split = filename.split("/");
            System.out.println("+++++++++++" + split[split.length - 1]);
            String url = getUrl(ossClient, FOLDER + split[split.length - 1]);
            System.out.println("阿里云图片路径:" + url);
        }
//        String key = FOLDER+"1afab7beed6f49469986f7c1a1e46ddc.jpg";
//        String url = getUrl(ossClient, key);
//        key ="youhuhu/be235e17c02048f3b98d353c69f56c28.jpg";
//        downloadFile(key, "D:/tt.jpg");
//        logger.info("阿里云图片路径:" + url);
//        //getIDcardWatermarkUrl(key);
    }
    
    /**
     * 获得水印图片url链接（身份证打马赛克）
     * 
     * @param key 文件在oos上的路径
     * @return
     */
    public static String getIDcardWatermarkUrl(String key) {
        OSSClient ossClient = getOSSClient();
        String mosaicKey = MOSAIC_FOLDER+"mosaic.png";
        String watermarkImg = Base64Utils.encodeToString(mosaicKey.getBytes());
        // 图片处理样式  
        String style = "image/resize,w_434/watermark,image_"+watermarkImg +",g_north,y_1";
        // 设置URL过期时间为10年 3600* 1000*24*365*10
        //Date expiration = new Date(new Date().getTime() + 3600 * 1000 * 24 * 365 * 10);
	   	 Calendar c = Calendar.getInstance();
		 Date data = c.getTime();
		 c.add(Calendar.YEAR, 50);
		 Date expiration = c.getTime();
        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(BACKET_NAME, key, HttpMethod.GET);
        req.setExpiration(expiration);
        req.setProcess(style);
        URL signedUrl = ossClient.generatePresignedUrl(req);
        if (signedUrl != null) {
            logger.info("访问路径："+signedUrl.toString());
            return signedUrl.toString();
        }
        return null;
    }

    /**
     * 
     * 功能描述: 获得水印图片url链接
     * 
     * @param imgKey 图片key
     * @param width  图片缩放宽度
     * @param mosaicKey 水印图片的key
     * @return String 返回打水印后的图片访问路径
     * @version 1.0.0
     * @author liuxl
     */
    public static String getWatermarkUrl(String imgKey,Integer width,String mosaicKey) {
        OSSClient ossClient = getOSSClient();
        String watermarkImg = Base64Utils.encodeToString(mosaicKey.getBytes());
        // 图片处理样式  
        String style = "image/resize,w_"+width+"/watermark,image_"+watermarkImg +",g_north,y_1";
        // 设置URL过期时间为10年 3600* 1000*24*365*10
        //Date expiration = new Date(new Date().getTime() + 3600 * 1000 * 24 * 365 * 10);
	   	 Calendar c = Calendar.getInstance();
		 Date data = c.getTime();
		 c.add(Calendar.YEAR, 50);
		 Date expiration = c.getTime();
        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(BACKET_NAME, imgKey, HttpMethod.GET);
        req.setExpiration(expiration);
        req.setProcess(style);
        URL signedUrl = ossClient.generatePresignedUrl(req);
        if (signedUrl != null) {
            logger.info("访问路径："+signedUrl.toString());
            return signedUrl.toString();
        }
        return null;
    }
    
    /**
     * 获得缩略图url链接（强制缩略成固定宽高）
     * 
     * @param key 文件在oos上的路径
     * @return
     * @throws IOException 
     */
    public static InputStream getImgIs(String key) throws IOException {
        
        OSSClient ossClient = getOSSClient();
        // 设置URL过期时间为10年 3600 * 1000*24*365*10
        //Date expiration = new Date(new Date().getTime() + 3600 * 1000 * 24 * 365 * 10);
	   	 Calendar c = Calendar.getInstance();
		 Date data = c.getTime();
		 c.add(Calendar.YEAR, 50);
		 Date expiration = c.getTime();
        
        // 图片处理样式  image/resize,m_fixed,h_100,w_100
        String style = "image/resize,m_lfit,h_"+400+",w_"+400;
        // 过期时间10分钟
        //Date expiration = new Date(new Date().getTime() + 1000 * 60 * 10 );
        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(BACKET_NAME, key, HttpMethod.GET);
        req.setExpiration(expiration);
        req.setProcess(style);
        URL url = ossClient.generatePresignedUrl(req);
        // 生成URL
//        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
//        InputStream bis = urlConnection.getInputStream();

        return url.openStream();
    }
    
    public static class UploadImgInfo{
      //原图oss访问路径
        private String url ;
        //oss 获取图片路径的key （folder+fileName）
        private String key ;
        //原图相对路径
        private String imgPath_original;
        //缩略图相对路径
        private String imgPath_thumbnail; 
        //缩略图oss访问路径
        private String url_thumbnail ;
        
        private String file_name;
        
        private String frontFlag ;
        
        public String getUrl() {
            return url;
        }
        public void setUrl(String url) {
            this.url = url;
        }
        public String getImgPath_original() {
            return imgPath_original;
        }
        public void setImgPath_original(String imgPath_original) {
            this.imgPath_original = imgPath_original;
        }
         
        public String getKey() {
            return key;
        }
        public void setKey(String key) {
            this.key = key;
        }
        public String getImgPath_thumbnail() {
            return imgPath_thumbnail;
        }
        public void setImgPath_thumbnail(String imgPath_thumbnail) {
            this.imgPath_thumbnail = imgPath_thumbnail;
        }
        public String getUrl_thumbnail() {
            return url_thumbnail;
        }
        public void setUrl_thumbnail(String url_thumbnail) {
            this.url_thumbnail = url_thumbnail;
        }
        public String getFile_name() {
            return file_name;
        }
        public void setFile_name(String file_name) {
            this.file_name = file_name;
        }
        public String getFrontFlag() {
            return frontFlag;
        }
        public void setFrontFlag(String frontFlag) {
            this.frontFlag = frontFlag;
        }
        
        
    }
    
    /** 
     * 上传OSS服务器文件 @Title: uploadFile  
     *  @param multipartFile spring 上传的文件 
     * remotePath @param oss服务器二级目录 
     *  @throws Exception 设定文件 @return String 
     * 返回类型 返回oss存放路径 @throws 
     */  
    public static String uploadFile(MultipartFile multipartfile ,String bucketName,String folder) throws Exception {  
         String resultStr = null;
         String url = null;
         try {
        	 OSSClient ossClient = getOSSClient();
             createBucketName(ossClient,bucketName);
             InputStream is = multipartfile.getInputStream();
             String orgName = multipartfile.getOriginalFilename();
             String ext = FilenameUtils.getExtension(orgName).toLowerCase();
             String fileName = "youhuhu_" + new Date().getTime() + orgName.substring(orgName.lastIndexOf("."));
             ObjectMetadata metadata = new ObjectMetadata();
             metadata.setContentLength(is.available());
             metadata.setCacheControl("no-cache");
             metadata.setHeader("Pragma", "no-cache");
             metadata.setContentEncoding("utf-8");
             metadata.setContentType(getContentType(fileName));
             PutObjectResult putResult = ossClient.putObject(bucketName, folder + fileName, is, metadata);
             System.out.println("上传解析结构+++++" + putResult);
             resultStr = putResult.getETag();
             if (StringUtils.isNotEmpty(resultStr)) {
                 String key = folder + fileName;
                 url = OssUtil.accessUrl+"/"+folder+fileName;
                 logger.info("阿里云上传后返回的url为："+url);
             } 
             ossClient.shutdown();
             is.close();
         } catch (Exception e) {
             e.printStackTrace();
             logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
         }
         return url;
    }  

    // 下载文件  
    public static void downloadFile(  
            String key, String filename) throws OSSException, ClientException {  
        OSSClient client = getOSSClient();
        client.getObject(new GetObjectRequest(BACKET_NAME, key), new File(  
                filename));  
    }  
    
}
